﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace Microsoft.WowAddonStudio.TocEditor
{
	/// <summary>
	/// This user control makes it possible to edit extended metadata tags
	/// in a grid.
	/// </summary>
	public partial class ExtendedTocMetaEditorUserControl : UserControl
	{
		#region Private member functions

		private readonly IMetadataManager manager;
		private DataTable sourceTable;
		private string selectedForDeletion;

		#endregion

		#region Lifecycle

		/// <summary>
		/// Constructor taking an <see cref="IMetadataManager"/> instance as its
		/// parameter and creating instances of <see cref="ExtendedTocMetaEditorUserControl"/>.
		/// </summary>
		/// <param name="manager">Manager that adds and removes metadata tags.</param>
		public ExtendedTocMetaEditorUserControl(IMetadataManager manager)
		{
			InitializeComponent();

			if (manager == null)
				throw new ArgumentNullException("manager");

			this.manager = manager;
			manager.OnMetadataChanged += Manager_OnMetadataChanged;
			DataBind();
		}

		/// <summary>
		/// Subscribes to grid events.
		/// </summary>
		private void SubscribeToGridEvents()
		{
			extendedMetadataGridView.UserAddedRow += extendedMetadataGridView_UserAddedRow;
			extendedMetadataGridView.UserDeletingRow += extendedMetadataGridView_UserDeletingRow;
			extendedMetadataGridView.UserDeletedRow += extendedMetadataGridView_UserDeletedRow;
			extendedMetadataGridView.CellEndEdit += extendedMetadataGridView_CellEndEdit;
		}

		/// <summary>
		/// Unsubscribes from grid events.
		/// </summary>
		private void UnsubscribeFromGridEvents()
		{
			extendedMetadataGridView.UserAddedRow -= extendedMetadataGridView_UserAddedRow;
			extendedMetadataGridView.UserDeletingRow -= extendedMetadataGridView_UserDeletingRow;
			extendedMetadataGridView.UserDeletedRow -= extendedMetadataGridView_UserDeletedRow;
			extendedMetadataGridView.CellEndEdit -= extendedMetadataGridView_CellEndEdit;
		}

		/// <summary>
		/// Handles the OnMetadataChanged event of the Manager control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="Microsoft.WowAddonStudio.TocEditor.MetadataManagerEventArgs"/> instance containing the event data.</param>
		private void Manager_OnMetadataChanged(object sender, MetadataManagerEventArgs e)
		{
			DataBind();
		}

		/// <summary>
		/// Datas the bind.
		/// </summary>
		private void DataBind()
		{
			UnsubscribeFromGridEvents();
			sourceTable = CreateTableFromTags(manager.GetExtendedTags());
			extendedMetadataGridView.DataSource = sourceTable;
			extendedMetadataGridView.Refresh();
			SubscribeToGridEvents();
		}

		#endregion

		#region Private member functions

		/// <summary>
		/// Creates the table from tags.
		/// </summary>
		/// <param name="tags">The tags.</param>
		/// <returns></returns>
		private static DataTable CreateTableFromTags(IEnumerable<KeyValuePair<string, string>> tags)
		{
			var result = new DataTable();
			result.Columns.Add("Name");
			result.Columns.Add("Value");

			foreach (var tag in tags)
			{
				DataRow dr = result.NewRow();
				dr[0] = tag.Key;
				dr[1] = tag.Value;
				result.Rows.Add(dr);
			}

			return result;
		}

		/// <summary>
		/// Handles the UserAddedRow event of the extendedMetadataGridView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.DataGridViewRowEventArgs"/> instance containing the event data.</param>
		private void extendedMetadataGridView_UserAddedRow(object sender, DataGridViewRowEventArgs e)
		{
			try
			{
				string selectedTagName = Convert.ToString(e.Row.Cells[0].Value);
				string selectedTagValue = Convert.ToString(e.Row.Cells[1].Value);

				if (!string.IsNullOrEmpty(selectedTagName))
					manager[selectedTagName] = selectedTagValue;
			}
			catch (Exception)
			{
				//At startup there are events that should not be there...
			}
		}

		/// <summary>
		/// Handles the UserDeletingRow event of the extendedMetadataGridView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.DataGridViewRowCancelEventArgs"/> instance containing the event data.</param>
		private void extendedMetadataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
		{
			try
			{
				selectedForDeletion = Convert.ToString(e.Row.Cells[0].Value);
			}
			catch (Exception)
			{
				selectedForDeletion = string.Empty;
			}
		}

		/// <summary>
		/// Handles the UserDeletedRow event of the extendedMetadataGridView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.DataGridViewRowEventArgs"/> instance containing the event data.</param>
		private void extendedMetadataGridView_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
		{
			manager.Remove(selectedForDeletion);
		}

		/// <summary>
		/// Handles the CellEndEdit event of the extendedMetadataGridView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellEventArgs"/> instance containing the event data.</param>
		private void extendedMetadataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
		{
			try
			{
				string selectedTagName = Convert.ToString(extendedMetadataGridView.Rows[e.RowIndex].Cells[0].Value);
				string selectedTagValue = null;
				try
				{
					selectedTagValue = (string) extendedMetadataGridView.Rows[e.RowIndex].Cells[1].Value;
				}
				catch (Exception)
				{
				}

				if (!string.IsNullOrEmpty(selectedTagName))
					manager[selectedTagName] = selectedTagValue;
			}
			catch (Exception)
			{
				//At startup there are events that should not be there...
			}
		}

		/// <summary>
		/// Handles the Opening event of the commonNameContextMenuStrip control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
		private void commonNameContextMenuStrip_Opening(object sender, CancelEventArgs e)
		{
			commonNameContextMenuStrip.Items.Clear();

			commonNameContextMenuStrip.Items.Add("Please choose common tag to insert");
			commonNameContextMenuStrip.Items[0].Enabled = false;

			//Filter items
			IEnumerable<string> filteredTags = TocTagName.GetCommonTagNames().Where(tagName => !InTable(tagName));
			foreach (var filteredTag in filteredTags)
			{
				commonNameContextMenuStrip.Items.Add(filteredTag);
			}
		}

		/// <summary>
		/// Ins the table.
		/// </summary>
		/// <param name="tagName">Name of the tag.</param>
		/// <returns></returns>
		private bool InTable(string tagName)
		{
			foreach (var row in extendedMetadataGridView.Rows)
			{
				try
				{
					var cellContent = (string) ((row as DataGridViewRow).Cells[0].Value);
					if (string.Compare(cellContent, tagName, StringComparison.OrdinalIgnoreCase) == 0)
						return true;
				}
				catch (InvalidCastException)
				{
					//DBNull cannot be cast...
				}
			}

			return false;
		}

		/// <summary>
		/// Handles the ItemClicked event of the commonNameContextMenuStrip control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.ToolStripItemClickedEventArgs"/> instance containing the event data.</param>
		private void commonNameContextMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
		{
			manager[e.ClickedItem.Text] = null;
		}

		#endregion
	}
}